package com.dayu.demo.service;

import java.util.ArrayList;
import java.math.BigDecimal;
import java.time.*;
import java.util.List;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import com.vecspace.utils.Assert;
import com.vecspace.utils.Convert;
import com.vecspace.utils.DateTimeUtil;
import com.vecspace.utils.NumberUtil;
import com.vecspace.utils.TJSON;
import com.vecspace.exception.HException;
import com.vecspace.exception.DBExceptionManager;
import com.vecspace.database.model.PojoManager;
import com.vecspace.data.model.FilterColumn;
import com.vecspace.data.model.ListExBO;
import com.vecspace.database.model.QueryResultAggregation;
import com.vecspace.security.model.LoginContext;
import com.vecspace.constant.AuthTag;
import com.vecspace.framework.sysdata.service.SysDataService;
import com.vecspace.data.model.DataLockState;
import com.dayu.demo.pojo.Project;
import com.dayu.demo.pojo.ProjectEx;
import com.dayu.demo.pojo.ProjectStats;
import com.dayu.demo.dao.ProjectDao;

/**功能描述 的增、删、改查等业务操作的service类
 * @template dayu-code-builder
 * @author user
 * @reviewer 
 * @createTime 2021-11-24 15:09:31
 * @version 1.0
 */
@Service("demo_projectService")
public class ProjectService {
    /** 根据ID查询 项目信息
     * @param id   主键值
     * @return Project
     * @throws Exception
     * @author user
     * @reviewer 
     * @createTime 2021-11-24 15:09:31
     */
    public Project getProject(Long id) throws Exception{
        Project project = projectDao.getProject(id);
        return project;
    }




    /**根据属性名获取字段值
     * @param id 记录id
     * @param propName 属性名
     * @return
     * @throws Exception
     * @author user
     * @reviewer
     * @createTime 2021-11-24 15:09:31
     */
    public Object getValueByProp(Long id, String propName) throws Exception {
    	return projectDao.getValueByProp(id, propName);
    }

    /**根据id更新指定字段的值（根据propName从pojo获取字段名）
     * @param id 记录id
     * @param propName 属性名
     * @param value 属性值
     * @throws Exception
     * @author user
     * @reviewer
     * @createTime 2021-11-24 15:09:31
     */
    public void updateValueByProp(Long id, String propName, Object value) throws Exception {
    	Object dbVal = value;
    	String[] propNames = new String[]{ "id","name","fullName","code","address","lng","lat","projectKind","salesManager","districtCode","projectManager","initialDate","bidDate","contractAmount","projectMonths","projectContent","projectStatus","projectScore","projectOwner","linkMan","linkPhone","abort","remarks","ordnum","rowLock" };
    	String[] datePropNames = new String[]{  };
    	String[] numberPropNames = new String[]{ "id","lng","lat","salesManager","projectManager","contractAmount","projectMonths","projectScore","ordnum","rowLock" };
    	if(ArrayUtils.indexOf(propNames, propName) < 0) throw new HException("属性名不正确:"+propName);
        if(ArrayUtils.indexOf(datePropNames, propName) >= 0 && value != null){
            if(value.getClass().equals(String.class)){
                dbVal = TJSON.convertToObject(LocalDateTime.class, String.format("\"{0}\"", value));
            }
        }
        if(ArrayUtils.indexOf(numberPropNames, propName) >= 0 && value != null){
            if(value.getClass().equals(String.class)){
                if(StringUtils.isNotBlank(value.toString())){
                    dbVal = new BigDecimal(value.toString());
                }else{
                    dbVal = null;
                }
            }
        }
    	projectDao.updateValueByProp(id, propName, dbVal);
    }

    /***将页面上传入的对象转为持久化对象（如果页面对象是一个新对象，则insert;否则从数据库库查询出已有的对象item2，将传入的值赋值给item2，然后将item2 update到数据库）
     * 根据页面上放置的属性个数，需要对下面的属性设置进行调整。
     * 对于无法在页面上进行修改的属性，不要进行设值。
     * @param item item是由页面传递过来的对象，item中的属性并不完整，对于在页面上没有展示的属性，item中一律会是空值，而数据库中这些属性可以是有值的
     * @return Project
     * @throws Exception
     * @author user
     * @reviewer 
     * @createTime 2021-11-24 15:09:31
     */
    public Project saveViewProject(Project item) throws Exception {
        if (item == null){
            return null;
        }
        /*** 下面开始对item对象的页面传值进行校验，如必填项，格式等 ***/
        //Assert.throwz(StringUtils.isNotBlank() , "条件不满足时抛出异常");
        /*** 结束校验 ***/
        
        Project item2;
        if (NumberUtil.isNotNullZero(item.getId())) {
            /**从数据库中取出原始对象，将从页面传过来的新值赋值给原始对象，并将原始对象再保存到数据库中 **/
            item2 = getProject(item.getId());
            if (item2 != null) {
                /*** 将页面上的新值逐一赋值，不在页面上的属性不要进行赋值 ***/
                item2.setName(item.getName());//更新项目简称
                item2.setFullName(item.getFullName());//更新项目全称
                item2.setCode(item.getCode());//更新项目编码
                item2.setAddress(item.getAddress());//更新项目地点
                item2.setLng(item.getLng());//更新经度
                item2.setLat(item.getLat());//更新纬度
                item2.setProjectKind(item.getProjectKind());//更新项目类型
                item2.setSalesManager(item.getSalesManager());//更新销售经理
                item2.setDistrictCode(item.getDistrictCode());//更新所在行政区
                item2.setProjectManager(item.getProjectManager());//更新项目经理
                item2.setInitialDate(item.getInitialDate());//更新立项日期
                item2.setBidDate(item.getBidDate());//更新中标日期
                item2.setContractAmount(item.getContractAmount());//更新合同金额
                item2.setProjectMonths(item.getProjectMonths());//更新项目周期
                item2.setProjectContent(item.getProjectContent());//更新项目建设内容
                item2.setProjectStatus(item.getProjectStatus());//更新项目状态
                item2.setProjectScore(item.getProjectScore());//更新项目评分
                item2.setProjectOwner(item.getProjectOwner());//更新业主单位
                item2.setLinkMan(item.getLinkMan());//更新联系人姓名
                item2.setLinkPhone(item.getLinkPhone());//更新联系人电话
                item2.setAbort(item.getAbort());//更新是否中止
                item2.setRemarks(item.getRemarks());//更新备注
                item2.setOrdnum(item.getOrdnum());//更新顺序号
                item2.setRowLock(item.getRowLock());//更新锁定状态
                /**end**/
            } else {
                item2 = item;
            }
        }else{ //item是新增加的对象
            item2 = item;
        }
        saveProject(item2);
        return item2;
    }

    /** 插入或修改  ，item中的所有属性都会更新到数据库中（包括属性值为null的，也会将null更新到数据库，覆盖之前的值）。
     * @param item    要保存的对象
     * @return void
     * @throws Exception
     * @author user
     * @reviewer 
     * @createTime 2021-11-24 15:09:31
     */
    public void saveProject(Project item) throws Exception{
        if (item == null){
            return;
        }
        /*** 下面开始对item对象进行校验，如逻辑关系等 ***/
        /*** 结束校验 ***/
        LocalDateTime dtime = LocalDateTime.now();
        if (NumberUtil.isNullOrZero(item.getId())) {
            item.setId(null);
            item.setCreateTime(dtime);  //创建时间
            String loginId = LoginContext.getLoginId();//创建人
            item.setCreateUser(loginId);
        } else {
        }
        try{
            projectDao.saveProject(item);
        }catch(Exception ex){
            //识别并转换数据库约束错误
            Exception ex2 = DBExceptionManager.parseException(ex);
            throw ex2;
        }
    }


    /**修改数据锁定状态
     * @param id 记录id，另-1表示对整表进行锁定
     * @param lockState
     * @param authTag 权限类型，参考 AuthTag
     * @author wanghua
     * @date 2021/11/17  20:45
     * @return void
     **/
	public void changeLockState(Long id, int lockState, int authTag) throws Exception {
        Assert.throwz(DataLockState.isValidState(lockState), "不是有效的锁定状态："+lockState);
        //权限验证，是否有选项更改锁定状态
        DataLockState.checkAuth(lockState, authTag);
        if(id != null && id > 0) {
            projectDao.updateValueByProp(id, "rowLock", lockState);
        }else{
            sysDataService.changeLockState(PojoManager.getTableName(Project.class), "", -1L, null, lockState);
        }
    }

    /** 根据ID删除 
     * @param id    主键值
     * @return void
     * @throws Exception
     * @author user
     * @reviewer 
     * @createTime 2021-11-24 15:09:31
     */
    public void deleteProject(Long id) throws Exception{
        projectDao.checkReferenced("T_DEMO_PROJECT", id);
        projectDao.deleteProject(id);
    }

    /**根据查询条件获取查询结果（分页查询），同时进行聚合统计查询
     * 
     
     
     * @param filterColumns 查询条件（字段和值）
     * @param pageIndex 查询第几页数据（从1开始）
     * @param pageSize 每页数据条数，-1表示不分页
     * @param sortField 排序字段
     * @param sortOrder 排序顺序
     * @return
     * @throws Exception 
     * @author user
     * @reviewer 
     * @createTime 2021-11-24 15:09:31
     */
    public ListExBO<ProjectEx, Void, ProjectStats> getProjectExListAndStats(List<FilterColumn> filterColumns,
        int pageIndex, int pageSize, String sortField, String sortOrder) throws Exception{

        if(pageSize > 10000){ //默认限制返回记录数不能超过10000条
            pageSize = 10000;
        }
        if(pageSize < 1){ //底层查询时-1表示不分页，但是为了避免返回海量数据，所以这里强制返回前10000条数据。
            pageSize = 1;
            pageSize = 10000;
        }
        if(sortField == null || sortField.length() == 0){
            //默认排序字段
            sortField = "id";
            sortOrder = "DESC";
        }else {
            //根据属性名获取字段名，则返回自身
            sortField = PojoManager.getColumnName(ProjectEx.class, sortField, sortField);
        }
        
        //将filterColumns中的ColumnName进行处理，如果值为propName，则替换为ColumnName
        FilterColumn.replaceFilterColumnName(ProjectEx.class, filterColumns);
             
        QueryResultAggregation<ProjectEx, ProjectStats> projectList = projectDao.getProjectExListAndStats(filterColumns, pageIndex, pageSize, sortField, sortOrder);

        //如果需要返回更多的内容，可以基于ListExBO实现自己的子类，然后返回子类对象
        ListExBO<ProjectEx, Void, ProjectStats> projectBOList = ListExBO.newInstance(projectList.getEntities(), projectList.getAggregateEntities(), projectList.getPagination());

        projectBOList.setAuthTag(AuthTag.All);//模板生成时默认设置为登录用户对此数据拥有最高权限。需要修改为根据权限系统获取权限。
        
        return projectBOList;
    }

    /** property **/
    @Autowired
    private ProjectDao projectDao;
    
    @Autowired
    private SysDataService sysDataService;
}
